import string

from django.dispatch import receiver
from django.utils.html import escape
from django.utils.translation import gettext_lazy as _
from django.utils.translation import ngettext_lazy as _n

from eventyay.base.models import (
    ActivityLog,
    Answer,
    AnswerOption,
    CfP,
    Event,
    MailTemplate,
    LogEntry,
    QueuedMail,
    Review,
    SpeakerProfile,
    Submission,
    SubmissionComment,
    SubmissionStates,
    TalkQuestion,
)
from eventyay.base.signals import activitylog_display, activitylog_object_link
from eventyay.common.text.phrases import phrases

# Usually, we don't have to include the object name in activity log
# strings, because we use ActivityLog.content_object to get the object
# and display it above the message. However, in some cases, like when
# we log the deletion of an object, we don't have the object anymore,
# so we'll want to format the message instead.
TEMPLATE_LOG_NAMES = {
    'pretalx.event.delete': _('The event {name} ({slug}) by {organiser} was deleted.'),
    'pretalx.organiser.delete': _('The organiser {name} was deleted.'),
}

# These log names were used in the past, and we still support them for display purposes
LOG_ALIASES = {
    'pretalx.event.invite.orga.accept': 'pretalx.invite.orga.accept',
    'pretalx.event.invite.orga.retract': 'pretalx.invite.orga.retract',
    'pretalx.event.invite.orga.send': 'pretalx.invite.orga.send',
    'pretalx.event.invite.reviewer.retract': 'pretalx.invite.reviewer.retract',
    'pretalx.event.invite.reviewer.send': 'pretalx.invite.reviewer.send',
    'pretalx.submission.confirmation': 'pretalx.submission.confirm',
    'pretalx.submission.answerupdate': 'pretalx.submission.answer.update',
    'pretalx.submission.answercreate': 'pretalx.submission.answer.create',
    # This isn't really the same thing, as the create takes place when the submission is
    # created, e.g. as a draft proposal, and the make_submitted takes place when the submission
    # is submitted to the CfP. But as we treat draft proposals as not existing at all
    # yet, we can treat this as a create action.
    'pretalx.submission.make_submitted': 'pretalx.submission.create',
}

LOG_NAMES = {
    'pretalx.cfp.update': _('The CfP has been modified.'),
    'pretalx.event.create': _('The event has been added.'),
    'pretalx.event.update': _('The event was modified.'),
    'pretalx.event.activate': _('The event was made public.'),
    'pretalx.event.deactivate': _('The event was deactivated.'),
    'pretalx.event.plugins.enabled': _('A plugin was enabled.'),
    'pretalx.event.plugins.disabled': _('A plugin was disabled.'),
    'pretalx.invite.orga.accept': _('The invitation to the event orga was accepted.'),
    'pretalx.invite.orga.retract': _('An invitation to the event orga was retracted.'),
    'pretalx.invite.orga.send': _('An invitation to the event orga was sent.'),
    'pretalx.invite.reviewer.retract': _('The invitation to the review team was retracted.'),
    'pretalx.invite.reviewer.send': _('The invitation to the review team was sent.'),
    'pretalx.team.member.remove': _('A team member was removed'),
    'pretalx.mail.create': _('An email was created.'),
    'pretalx.mail.delete': _('A pending email was deleted.'),
    'pretalx.mail.delete_all': _('All pending emails were deleted.'),
    'pretalx.mail.sent': _('An email was sent.'),
    'pretalx.mail.update': _('An email was modified.'),
    'pretalx.mail_template.create': _('A mail template was added.'),
    'pretalx.mail_template.delete': _('A mail template was deleted.'),
    'pretalx.mail_template.update': _('A mail template was modified.'),
    'pretalx.question.create': _('A custom field was added.'),
    'pretalx.question.delete': _('A custom field was deleted.'),
    'pretalx.question.update': _('A custom field was modified.'),
    'pretalx.question.option.create': _('A custom field option was added.'),
    'pretalx.question.option.delete': _('A custom field option was deleted.'),
    'pretalx.question.option.update': _('A custom field option was modified.'),
    'pretalx.tag.create': _('A tag was added.'),
    'pretalx.tag.delete': _('A tag was deleted.'),
    'pretalx.tag.update': _('A tag was modified.'),
    'pretalx.room.create': _('A new room was added.'),
    'pretalx.room.update': _('A room was modified.'),
    'pretalx.room.delete': _('A room was deleted.'),
    'pretalx.schedule.release': _('A new schedule version was released.'),
    'pretalx.submission.accept': _('The proposal was accepted.'),
    'pretalx.submission.cancel': _('The proposal was cancelled.'),
    'pretalx.submission.confirm': _('The proposal was confirmed.'),
    'pretalx.submission.create': _('The proposal was added.'),
    'pretalx.submission.deleted': _('The proposal was deleted.'),
    'pretalx.submission.reject': _('The proposal was rejected.'),
    'pretalx.submission.resource.create': _('A proposal resource was added.'),
    'pretalx.submission.resource.delete': _('A proposal resource was deleted.'),
    'pretalx.submission.resource.update': _('A proposal resource was modified.'),
    'pretalx.submission.review.delete': _('A review was deleted.'),
    'pretalx.submission.review.update': _('A review was modified.'),
    'pretalx.submission.review.create': _('A review was added.'),
    'pretalx.submission.speakers.add': _('A speaker was added to the proposal.'),
    'pretalx.submission.speakers.invite': _('A speaker was invited to the proposal.'),
    'pretalx.submission.speakers.remove': _('A speaker was removed from the proposal.'),
    'pretalx.submission.unconfirm': _('The proposal was unconfirmed.'),
    'pretalx.submission.update': _('The proposal was modified.'),
    'pretalx.submission.withdraw': _('The proposal was withdrawn.'),
    'pretalx.submission.answer.update': _('A custom field response was modified.'),
    'pretalx.submission.answer.create': _('A custom field response was added.'),
    'pretalx.submission.comment.create': _('A proposal comment was added.'),
    'pretalx.submission.comment.delete': _('A proposal comment was deleted.'),
    'pretalx.submission_type.create': _('A session type was added.'),
    'pretalx.submission_type.delete': _('A session type was deleted.'),
    'pretalx.submission_type.make_default': _('The session type was made default.'),
    'pretalx.submission_type.update': _('A session type was modified.'),
    'pretalx.access_code.create': _('An access code was added.'),
    'pretalx.access_code.send': _('An access code was sent.'),
    'pretalx.access_code.update': _('An access code was modified.'),
    'pretalx.access_code.delete': _('An access code was deleted.'),
    'pretalx.track.create': _('A track was added.'),
    'pretalx.track.delete': _('A track was deleted.'),
    'pretalx.track.update': _('A track was modified.'),
    'pretalx.speaker.arrived': _('A speaker has been marked as arrived.'),
    'pretalx.speaker.unarrived': _('A speaker has been marked as not arrived.'),
    'pretalx.speaker_information.create': _('A speaker information note was added.'),
    'pretalx.speaker_information.update': _('A speaker information note was modified.'),
    'pretalx.speaker_information.delete': _('A speaker information note was deleted.'),
    'pretalx.user.token.reset': _('The API token was reset.'),
    'pretalx.user.token.revoke': _('The API token was revoked.'),
    'pretalx.user.token.upgrade': _('The API token was upgraded to the latest version.'),
    'pretalx.user.password.reset': phrases.base.password_reset_success,
    'pretalx.user.password.update': _('The password was modified.'),
    'pretalx.user.profile.update': _('The profile was modified.'),
}


@receiver(activitylog_display)
def default_activitylog_display(sender: Event, activitylog: LogEntry, **kwargs):
    if templated_entry := TEMPLATE_LOG_NAMES.get(activitylog.action_type):
        message = str(templated_entry)
        # Check if all placeholders are present in activitylog.data
        placeholders = {v[1] for v in string.Formatter().parse(message) if v[1]}
        if placeholders <= set(activitylog.json_data.keys()):
            return message.format(**activitylog.json_data)
    action_type = LOG_ALIASES.get(activitylog.action_type, activitylog.action_type)
    return LOG_NAMES.get(action_type)


def _submission_label_text(submission: Submission) -> str:
    if submission.state in (
        SubmissionStates.ACCEPTED,
        SubmissionStates.CONFIRMED,
    ):
        return _n('Session', 'Sessions', 1)
    else:
        return _n('Proposal', 'Proposals', 1)


@receiver(activitylog_object_link)
def default_activitylog_object_link(sender: Event, activitylog: LogEntry, **kwargs):
    if not activitylog.content_object:
        return
    url = ''
    text = ''
    link_text = ''
    if isinstance(activitylog.content_object, Submission):
        url = activitylog.content_object.orga_urls.base
        link_text = escape(activitylog.content_object.title)
        text = _submission_label_text(activitylog.content_object)
    elif isinstance(activitylog.content_object, SubmissionComment):
        url = activitylog.content_object.submission.orga_urls.comments + f'#comment-{activitylog.content_object.pk}'
        link_text = escape(activitylog.content_object.submission.title)
        text = _submission_label_text(activitylog.content_object.submission)
    elif isinstance(activitylog.content_object, Review):
        url = activitylog.content_object.submission.orga_urls.reviews
        link_text = escape(activitylog.content_object.submission.title)
        text = _submission_label_text(activitylog.content_object.submission)
    elif isinstance(activitylog.content_object, TalkQuestion):
        url = activitylog.content_object.urls.base
        link_text = escape(activitylog.content_object.question)
        text = _('Custom field')
    elif isinstance(activitylog.content_object, AnswerOption):
        url = activitylog.content_object.question.urls.base
        link_text = escape(activitylog.content_object.question.question)
        text = _('Custom field')
    elif isinstance(activitylog.content_object, Answer):
        if activitylog.content_object.submission:
            url = activitylog.content_object.submission.orga_urls.base
        else:
            url = activitylog.content_object.question.urls.base
        link_text = escape(activitylog.content_object.question.question)
        text = _('Response to custom field')
    elif isinstance(activitylog.content_object, CfP):
        url = activitylog.content_object.urls.text
        link_text = _('Call for Proposals')
    elif isinstance(activitylog.content_object, MailTemplate):
        url = activitylog.content_object.urls.base
        text = _('Mail template')
        link_text = escape(activitylog.content_object.subject)
    elif isinstance(activitylog.content_object, QueuedMail):
        url = activitylog.content_object.urls.base
        text = _('Email')
        link_text = escape(activitylog.content_object.subject)
    elif isinstance(activitylog.content_object, SpeakerProfile):
        url = activitylog.content_object.orga_urls.base
        text = _('Speaker profile')
        link_text = escape(activitylog.content_object.user.get_display_name())
    elif isinstance(activitylog.content_object, Event):
        url = activitylog.content_object.orga_urls.base
        text = _('Event')
        link_text = escape(activitylog.content_object.name)
    if url:
        if not link_text:
            link_text = url
        return f'{text} <a href="{url}">{link_text}</a>'
    if text or link_text:
        return f'{text} {link_text}'
